Preparations

knitr::opts_knit$set(root.dir = rprojroot::find_rstudio_root_file(), 
                     fig.width=14,
                     fig.height=14)
set.seed(42)
library(tidyverse)

Read data

tx_gene_meta <- read_csv("./data/hg_ens97_metadata.txt")
Parsed with column specification:
cols(
  tx_id = col_character(),
  gene_name = col_character(),
  gene_len = col_double(),
  premrna_len = col_double(),
  intronic_len = col_double(),
  exonic_len = col_double(),
  cds_len = col_double(),
  utr5_len = col_double(),
  utr3_len = col_double(),
  nexon = col_double(),
  nintron = col_double(),
  perc_gene_gc = col_double(),
  gene_id = col_character(),
  seqnames = col_character(),
  gene_biotype = col_character(),
  tx_biotype = col_character(),
  tx_id_version = col_character()
)
tx_gene_meta

Gene Level

Extract Gene metadata

gene_meta <- 
  tx_gene_meta %>%
         dplyr::group_by(gene_id) %>%
         dplyr::slice(1) %>%
  ungroup() %>%
  select(gene_name, gene_len, perc_gene_gc, gene_id, seqnames, gene_biotype)
gene_meta

Some gene names are not unique

duplicated_gene_names <-
  gene_meta %>%
  dplyr::filter( duplicated(gene_name))%>%
  pull(gene_name)%>%
  unique()
  

length(duplicated_gene_names)
[1] 970
gene_meta %>%
  dplyr::filter(gene_name%in% duplicated_gene_names ) %>%
  arrange(gene_name)

Gene Biotypes

biotype_count <-
  gene_meta %>% 
  group_by(gene_biotype) %>% 
  tally(sort = TRUE)
biotype_count
biotype_targets <-
  biotype_count %>%
  slice(1:10)%>% 
  pull(gene_biotype)

Percentage of Gene GC Content

ggplot(gene_meta %>%
         filter(gene_biotype %in% biotype_targets),
       aes(perc_gene_gc)) +
  geom_histogram(bins = 150)   +
  facet_wrap(~gene_biotype)

ggplot(gene_meta %>%
         filter(gene_biotype %in% biotype_targets) ,
       aes(gene_len)) +
  geom_histogram(bins = 150)  +  
   scale_x_log10() +
  facet_wrap(~gene_biotype)

ggplot(gene_meta %>%
         filter(gene_biotype %in% biotype_targets), 
       aes(perc_gene_gc, gene_len))+
  geom_point(size=0.8,
              alpha=0.7) +
  geom_density_2d() +  
   scale_y_log10() +
   theme(legend.position="none") +
  facet_wrap(~gene_biotype)

Transcript Level

Transcript Biotypes

tx_biotype_count <-
  tx_gene_meta %>% 
  group_by(tx_biotype) %>% 
  tally(sort = TRUE)
tx_biotype_count
tx_biotype_targets <-
  tx_biotype_count %>%
  slice(1:8)%>% 
  pull(tx_biotype)

Exonic vs intronic lengths

ggplot(tx_gene_meta %>%
         filter(tx_biotype %in% tx_biotype_targets)) +
  geom_point( aes(exonic_len, intronic_len, colour=perc_gene_gc),
              size=0.3,
              alpha=0.6)  +  
  scale_x_log10() +
   scale_y_log10() +
  facet_wrap(~tx_biotype) +
  scale_colour_gradient2(midpoint=10, mid = "yellow")

Exonic vs intronic counts

ggplot(tx_gene_meta %>%
         filter(tx_biotype %in% tx_biotype_targets)) +
  geom_point( aes(nexon, nintron, colour=gene_len),
              size=0.8,
              alpha=0.7)  +  
  scale_x_log10() +
   scale_y_log10()  +
  facet_wrap(~tx_biotype) 

Pre-mRNA vs Exonic lengths

ggplot(tx_gene_meta %>%
         filter(tx_biotype %in% tx_biotype_targets & nexon!=1),
       aes( premrna_len, exonic_len, colour=nexon)) +
  geom_point( size=0.1,
              alpha=0.3)  +    
  geom_density_2d() +  
  scale_x_log10() +
   scale_y_log10() +
  facet_wrap(~tx_biotype) 

Exonic Counts vs Exonic lengths

ggplot(tx_gene_meta %>%
         filter(tx_biotype %in% tx_biotype_targets ),
       aes( nexon, exonic_len, colour=premrna_len)) +
  geom_point( size=0.1,
              alpha=0.3)  +    
  scale_x_log10() +
   scale_y_log10() +
  facet_wrap(~tx_biotype) 

Number of transcipts by gene

count_tx_by_gene <-
  tx_gene_meta %>%
  count(gene_id,gene_name, gene_biotype) %>%
  arrange(-n)
count_tx_by_gene 
ggplot(count_tx_by_gene, aes(n)) +
  geom_histogram(bins = 100)  

top_genes <- 
  count_tx_by_gene %>%
  slice(1:20) %>%
  pull(gene_name)
top_genes
 [1] "PCBP1-AS1" "MAPK10"    "TEX41"     "PVT1"      "LINC00635" "MIR663AHG" "MIR99AHG"  "SNHG14"    "MUC20-OT1" "LINC00343" "LINC00293" "HULC"      "LINC00511"
[14] "CASC15"    "SOX2-OT"   "LINC01206" "SGCE"      "SPG7"      "KCNMA1"    "TCF4"     
ggplot(tx_gene_meta %>% 
         dplyr::filter(gene_name%in% top_genes))+
  geom_point( aes(exonic_len, intronic_len, colour=nexon >=10)) +
  facet_wrap(gene_biotype~gene_name,   scales = "free")

tx_10_genes <- 
  count_tx_by_gene %>%
  filter(n==10) %>%
  slice(1:20) %>%
  pull(gene_name)
ggplot(tx_gene_meta %>% 
         dplyr::filter(gene_name%in% tx_10_genes))+
  geom_point( aes(exonic_len, intronic_len, colour=nexon >=10)) +
  facet_wrap(~gene_name,  scales = "free") 

NA
single_transcript_genes <-
  count_tx_by_gene %>% 
  dplyr::filter(n==1) %>% 
  pull(gene_name)
length(single_transcript_genes)
[1] 37383
ggplot(tx_gene_meta  %>% 
         dplyr::filter(gene_name%in% single_transcript_genes & gene_biotype %in% biotype_targets ))+
  geom_point( aes(exonic_len, intronic_len,  colour=perc_gene_gc),
              size=0.2,
              alpha=0.5)  +  
  scale_x_log10() +
   scale_y_log10() +
  facet_wrap(~tx_biotype)  +
  scale_colour_gradient2(midpoint=10, mid = "yellow")

Single exon transcripts

  tx_gene_meta %>%
  count(nexon ) %>%
  arrange(-n)
ggplot(tx_gene_meta %>% 
         dplyr::filter(tx_biotype %in% tx_biotype_targets & nexon== 2)) +
  geom_point( aes(exonic_len, intronic_len,  colour=perc_gene_gc),
              size=0.2,
              alpha=0.5)  +  
  scale_x_log10() +
   scale_y_log10() +
  facet_wrap(~tx_biotype)  +
  scale_colour_gradient2(midpoint=10, mid = "yellow")

ggplot(tx_gene_meta %>% 
         dplyr::filter(tx_biotype %in% tx_biotype_targets & nexon< 10 & nexon> 1)) +
  geom_point( aes(exonic_len, intronic_len,  colour=perc_gene_gc),
              size=0.2,
              alpha=0.5)  +  
  scale_x_log10() +
   scale_y_log10() +
  facet_wrap(~tx_biotype)  +
  scale_colour_gradient2(midpoint=10, mid = "yellow")

ggplot(tx_gene_meta %>% 
         dplyr::filter(tx_biotype %in% tx_biotype_targets & nexon>= 10)) +
  geom_point( aes(exonic_len, intronic_len,  colour=perc_gene_gc),
              size=0.2,
              alpha=0.5)  +  
  scale_x_log10() +
   scale_y_log10() +
  facet_wrap(~tx_biotype)  +
  scale_colour_gradient2(midpoint=10, mid = "yellow")

sessionInfo()
R version 3.6.1 (2019-07-05)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 18.04.3 LTS

Matrix products: default
BLAS:   /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.7.1
LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.7.1

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C               LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8     LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
 [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                  LC_ADDRESS=C               LC_TELEPHONE=C             LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] forcats_0.4.0   stringr_1.4.0   dplyr_0.8.3     purrr_0.3.2     readr_1.3.1     tidyr_0.8.3     tibble_2.1.3    ggplot2_3.2.1   tidyverse_1.2.1

loaded via a namespace (and not attached):
 [1] Rcpp_1.0.2       cellranger_1.1.0 pillar_1.4.2     compiler_3.6.1   tools_3.6.1      digest_0.6.20    zeallot_0.1.0    lubridate_1.7.4  jsonlite_1.6    
[10] nlme_3.1-140     gtable_0.3.0     lattice_0.20-38  pkgconfig_2.0.2  rlang_0.4.0      cli_1.1.0        rstudioapi_0.10  haven_2.1.1      xfun_0.8        
[19] withr_2.1.2      xml2_1.2.2       httr_1.4.1       knitr_1.24       generics_0.0.2   vctrs_0.2.0      hms_0.5.0        rprojroot_1.3-2  grid_3.6.1      
[28] tidyselect_0.2.5 glue_1.3.1       R6_2.4.0         readxl_1.3.1     modelr_0.1.5     magrittr_1.5     MASS_7.3-51.4    backports_1.1.4  scales_1.0.0    
[37] rvest_0.3.4      assertthat_0.2.1 colorspace_1.4-1 labeling_0.3     stringi_1.4.3    lazyeval_0.2.2   munsell_0.5.0    broom_0.5.2      crayon_1.3.4    
LS0tCnRpdGxlOiAiRXhwbG9yZSBodW1hbiBtZXRhZGF0YSIKYXV0aG9yOiAKLSBuYW1lOiBSaWNrIEZhcm91bmkKICBhZmZpbGlhdGlvbjoKICAtICZjcnVrIERlcGFydG1lbnQgb2YgSHVtYW4gR2VuZXRpY3MsIE1jR2lsbCBVbml2ZXJzaXR5LCAgTW9udHJlYWwsIENhbmFkYQpkYXRlOiAnYHIgZm9ybWF0KFN5cy5EYXRlKCksICIlWS0lQi0lZCIpYCcKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKCiMgUHJlcGFyYXRpb25zCgpgYGB7ciBzZXR1cH0Ka25pdHI6Om9wdHNfa25pdCRzZXQocm9vdC5kaXIgPSBycHJvanJvb3Q6OmZpbmRfcnN0dWRpb19yb290X2ZpbGUoKSwgCiAgICAgICAgICAgICAgICAgICAgIGZpZy53aWR0aD0xNCwKICAgICAgICAgICAgICAgICAgICAgZmlnLmhlaWdodD0xNCkKc2V0LnNlZWQoNDIpCmBgYAoKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKQpgYGAKCgojIyBSZWFkIGRhdGEKCgoKYGBge3IgbWVzc2FnZT1UUlVFfQp0eF9nZW5lX21ldGEgPC0gcmVhZF9jc3YoIi4vZGF0YS9oZ19lbnM5N19tZXRhZGF0YS50eHQiKQp0eF9nZW5lX21ldGEKYGBgCgojIEdlbmUgTGV2ZWwgCgojIyBFeHRyYWN0IEdlbmUgbWV0YWRhdGEKCmBgYHtyfQpnZW5lX21ldGEgPC0gCiAgdHhfZ2VuZV9tZXRhICU+JQogICAgICAgICBkcGx5cjo6Z3JvdXBfYnkoZ2VuZV9pZCkgJT4lCiAgICAgICAgIGRwbHlyOjpzbGljZSgxKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgc2VsZWN0KGdlbmVfbmFtZSwgZ2VuZV9sZW4sIHBlcmNfZ2VuZV9nYywgZ2VuZV9pZCwgc2VxbmFtZXMsIGdlbmVfYmlvdHlwZSkKZ2VuZV9tZXRhCmBgYAoKClNvbWUgZ2VuZSBuYW1lcyBhcmUgbm90IHVuaXF1ZQoKYGBge3J9CmR1cGxpY2F0ZWRfZ2VuZV9uYW1lcyA8LQogIGdlbmVfbWV0YSAlPiUKICBkcGx5cjo6ZmlsdGVyKCBkdXBsaWNhdGVkKGdlbmVfbmFtZSkpJT4lCiAgcHVsbChnZW5lX25hbWUpJT4lCiAgdW5pcXVlKCkKICAKCmxlbmd0aChkdXBsaWNhdGVkX2dlbmVfbmFtZXMpCmBgYAoKYGBge3J9CmdlbmVfbWV0YSAlPiUKICBkcGx5cjo6ZmlsdGVyKGdlbmVfbmFtZSVpbiUgZHVwbGljYXRlZF9nZW5lX25hbWVzICkgJT4lCiAgYXJyYW5nZShnZW5lX25hbWUpCmBgYAoKCiMjIyBHZW5lIEJpb3R5cGVzCgoKYGBge3J9CmJpb3R5cGVfY291bnQgPC0KICBnZW5lX21ldGEgJT4lIAogIGdyb3VwX2J5KGdlbmVfYmlvdHlwZSkgJT4lIAogIHRhbGx5KHNvcnQgPSBUUlVFKQpiaW90eXBlX2NvdW50CmBgYAoKYGBge3J9CmJpb3R5cGVfdGFyZ2V0cyA8LQogIGJpb3R5cGVfY291bnQgJT4lCiAgc2xpY2UoMToxMCklPiUgCiAgcHVsbChnZW5lX2Jpb3R5cGUpCmBgYAoKCgojIyMgUGVyY2VudGFnZSBvZiBHZW5lIEdDIENvbnRlbnQKCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9MTJ9CmdncGxvdChnZW5lX21ldGEgJT4lCiAgICAgICAgIGZpbHRlcihnZW5lX2Jpb3R5cGUgJWluJSBiaW90eXBlX3RhcmdldHMpLAogICAgICAgYWVzKHBlcmNfZ2VuZV9nYykpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMTUwKSAgICsKICBmYWNldF93cmFwKH5nZW5lX2Jpb3R5cGUpCmBgYAoKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xMn0KZ2dwbG90KGdlbmVfbWV0YSAlPiUKICAgICAgICAgZmlsdGVyKGdlbmVfYmlvdHlwZSAlaW4lIGJpb3R5cGVfdGFyZ2V0cykgLAogICAgICAgYWVzKGdlbmVfbGVuKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAxNTApICArICAKICAgc2NhbGVfeF9sb2cxMCgpICsKICBmYWNldF93cmFwKH5nZW5lX2Jpb3R5cGUpCmBgYAoKYGBge3IsIGZpZy53aWR0aD0yMH0KZ2dwbG90KGdlbmVfbWV0YSAlPiUKICAgICAgICAgZmlsdGVyKGdlbmVfYmlvdHlwZSAlaW4lIGJpb3R5cGVfdGFyZ2V0cyksIAogICAgICAgYWVzKHBlcmNfZ2VuZV9nYywgZ2VuZV9sZW4pKSsKICBnZW9tX3BvaW50KHNpemU9MC44LAogICAgICAgICAgICAgIGFscGhhPTAuNykgKwogIGdlb21fZGVuc2l0eV8yZCgpICsgIAogICBzY2FsZV95X2xvZzEwKCkgKwogICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSArCiAgZmFjZXRfd3JhcCh+Z2VuZV9iaW90eXBlKQpgYGAKCgoKIyBUcmFuc2NyaXB0IExldmVsIAoKIyMjIFRyYW5zY3JpcHQgQmlvdHlwZXMKCgpgYGB7cn0KdHhfYmlvdHlwZV9jb3VudCA8LQogIHR4X2dlbmVfbWV0YSAlPiUgCiAgZ3JvdXBfYnkodHhfYmlvdHlwZSkgJT4lIAogIHRhbGx5KHNvcnQgPSBUUlVFKQp0eF9iaW90eXBlX2NvdW50CmBgYAoKYGBge3J9CnR4X2Jpb3R5cGVfdGFyZ2V0cyA8LQogIHR4X2Jpb3R5cGVfY291bnQgJT4lCiAgc2xpY2UoMTo4KSU+JSAKICBwdWxsKHR4X2Jpb3R5cGUpCmBgYAoKIyMgRXhvbmljIHZzIGludHJvbmljIGxlbmd0aHMKCmBgYHtyLCBmaWcud2lkdGg9MTZ9CmdncGxvdCh0eF9nZW5lX21ldGEgJT4lCiAgICAgICAgIGZpbHRlcih0eF9iaW90eXBlICVpbiUgdHhfYmlvdHlwZV90YXJnZXRzKSkgKwogIGdlb21fcG9pbnQoIGFlcyhleG9uaWNfbGVuLCBpbnRyb25pY19sZW4sIGNvbG91cj1wZXJjX2dlbmVfZ2MpLAogICAgICAgICAgICAgIHNpemU9MC4zLAogICAgICAgICAgICAgIGFscGhhPTAuNikgICsgIAogIHNjYWxlX3hfbG9nMTAoKSArCiAgIHNjYWxlX3lfbG9nMTAoKSArCiAgZmFjZXRfd3JhcCh+dHhfYmlvdHlwZSkgKwogIHNjYWxlX2NvbG91cl9ncmFkaWVudDIobWlkcG9pbnQ9MTAsIG1pZCA9ICJ5ZWxsb3ciKQoKYGBgCgoKCgoKCgoKIyMgRXhvbmljIHZzIGludHJvbmljIGNvdW50cwoKCmBgYHtyLCBmaWcud2lkdGg9MjB9CmdncGxvdCh0eF9nZW5lX21ldGEgJT4lCiAgICAgICAgIGZpbHRlcih0eF9iaW90eXBlICVpbiUgdHhfYmlvdHlwZV90YXJnZXRzKSkgKwogIGdlb21fcG9pbnQoIGFlcyhuZXhvbiwgbmludHJvbiwgY29sb3VyPWdlbmVfbGVuKSwKICAgICAgICAgICAgICBzaXplPTAuOCwKICAgICAgICAgICAgICBhbHBoYT0wLjcpICArICAKICBzY2FsZV94X2xvZzEwKCkgKwogICBzY2FsZV95X2xvZzEwKCkgICsKICBmYWNldF93cmFwKH50eF9iaW90eXBlKSAKYGBgCgoKIyMgUHJlLW1STkEgdnMgRXhvbmljIGxlbmd0aHMKCgpgYGB7ciwgZmlnLndpZHRoPTIwfQpnZ3Bsb3QodHhfZ2VuZV9tZXRhICU+JQogICAgICAgICBmaWx0ZXIodHhfYmlvdHlwZSAlaW4lIHR4X2Jpb3R5cGVfdGFyZ2V0cyAmIG5leG9uIT0xKSwKICAgICAgIGFlcyggcHJlbXJuYV9sZW4sIGV4b25pY19sZW4sIGNvbG91cj1uZXhvbikpICsKICBnZW9tX3BvaW50KCBzaXplPTAuMSwKICAgICAgICAgICAgICBhbHBoYT0wLjMpICArICAgIAogIGdlb21fZGVuc2l0eV8yZCgpICsgIAogIHNjYWxlX3hfbG9nMTAoKSArCiAgIHNjYWxlX3lfbG9nMTAoKSArCiAgZmFjZXRfd3JhcCh+dHhfYmlvdHlwZSkgCmBgYAoKIyMgRXhvbmljIENvdW50cyB2cyBFeG9uaWMgbGVuZ3RocwoKCmBgYHtyLCBmaWcud2lkdGg9MjB9CmdncGxvdCh0eF9nZW5lX21ldGEgJT4lCiAgICAgICAgIGZpbHRlcih0eF9iaW90eXBlICVpbiUgdHhfYmlvdHlwZV90YXJnZXRzICksCiAgICAgICBhZXMoIG5leG9uLCBleG9uaWNfbGVuLCBjb2xvdXI9cHJlbXJuYV9sZW4pKSArCiAgZ2VvbV9wb2ludCggc2l6ZT0wLjEsCiAgICAgICAgICAgICAgYWxwaGE9MC4zKSAgKyAgICAKICBzY2FsZV94X2xvZzEwKCkgKwogICBzY2FsZV95X2xvZzEwKCkgKwogIGZhY2V0X3dyYXAofnR4X2Jpb3R5cGUpIApgYGAKIyMgTnVtYmVyIG9mIHRyYW5zY2lwdHMgYnkgZ2VuZQoKYGBge3J9CmNvdW50X3R4X2J5X2dlbmUgPC0KICB0eF9nZW5lX21ldGEgJT4lCiAgY291bnQoZ2VuZV9pZCxnZW5lX25hbWUsIGdlbmVfYmlvdHlwZSkgJT4lCiAgYXJyYW5nZSgtbikKY291bnRfdHhfYnlfZ2VuZSAKYGBgCgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9N30KZ2dwbG90KGNvdW50X3R4X2J5X2dlbmUsIGFlcyhuKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAxMDApICAKYGBgCmBgYHtyfQp0b3BfZ2VuZXMgPC0gCiAgY291bnRfdHhfYnlfZ2VuZSAlPiUKICBzbGljZSgxOjIwKSAlPiUKICBwdWxsKGdlbmVfbmFtZSkKdG9wX2dlbmVzCmBgYAoKCmBgYHtyIGZpZy5oZWlnaHQ9MTV9CmdncGxvdCh0eF9nZW5lX21ldGEgJT4lIAogICAgICAgICBkcGx5cjo6ZmlsdGVyKGdlbmVfbmFtZSVpbiUgdG9wX2dlbmVzKSkrCiAgZ2VvbV9wb2ludCggYWVzKGV4b25pY19sZW4sIGludHJvbmljX2xlbiwgY29sb3VyPW5leG9uID49MTApKSArCiAgZmFjZXRfd3JhcChnZW5lX2Jpb3R5cGV+Z2VuZV9uYW1lLCAgIHNjYWxlcyA9ICJmcmVlIikKYGBgCgoKCgpgYGB7cn0KdHhfMTBfZ2VuZXMgPC0gCiAgY291bnRfdHhfYnlfZ2VuZSAlPiUKICBmaWx0ZXIobj09MTApICU+JQogIHNsaWNlKDE6MjApICU+JQogIHB1bGwoZ2VuZV9uYW1lKQpgYGAKCgoKYGBge3IgZmlnLmhlaWdodD0xNX0KZ2dwbG90KHR4X2dlbmVfbWV0YSAlPiUgCiAgICAgICAgIGRwbHlyOjpmaWx0ZXIoZ2VuZV9uYW1lJWluJSB0eF8xMF9nZW5lcykpKwogIGdlb21fcG9pbnQoIGFlcyhleG9uaWNfbGVuLCBpbnRyb25pY19sZW4sIGNvbG91cj1uZXhvbiA+PTEwKSkgKwogIGZhY2V0X3dyYXAofmdlbmVfbmFtZSwgIHNjYWxlcyA9ICJmcmVlIikgCiAgCmBgYAoKCmBgYHtyfQpzaW5nbGVfdHJhbnNjcmlwdF9nZW5lcyA8LQogIGNvdW50X3R4X2J5X2dlbmUgJT4lIAogIGRwbHlyOjpmaWx0ZXIobj09MSkgJT4lIAogIHB1bGwoZ2VuZV9uYW1lKQpsZW5ndGgoc2luZ2xlX3RyYW5zY3JpcHRfZ2VuZXMpCmBgYAoKCgpgYGB7ciBmaWcuaGVpZ2h0PTh9CmdncGxvdCh0eF9nZW5lX21ldGEgICU+JSAKICAgICAgICAgZHBseXI6OmZpbHRlcihnZW5lX25hbWUlaW4lIHNpbmdsZV90cmFuc2NyaXB0X2dlbmVzICYgZ2VuZV9iaW90eXBlICVpbiUgYmlvdHlwZV90YXJnZXRzICkpKwogIGdlb21fcG9pbnQoIGFlcyhleG9uaWNfbGVuLCBpbnRyb25pY19sZW4sICBjb2xvdXI9cGVyY19nZW5lX2djKSwKICAgICAgICAgICAgICBzaXplPTAuMiwKICAgICAgICAgICAgICBhbHBoYT0wLjUpICArICAKICBzY2FsZV94X2xvZzEwKCkgKwogICBzY2FsZV95X2xvZzEwKCkgKwogIGZhY2V0X3dyYXAofnR4X2Jpb3R5cGUpICArCiAgc2NhbGVfY29sb3VyX2dyYWRpZW50MihtaWRwb2ludD0xMCwgbWlkID0gInllbGxvdyIpCgpgYGAKCiMgU2luZ2xlIGV4b24gdHJhbnNjcmlwdHMKCgpgYGB7cn0KICB0eF9nZW5lX21ldGEgJT4lCiAgY291bnQobmV4b24gKSAlPiUKICBhcnJhbmdlKC1uKQpgYGAKCgoKCmBgYHtyIGZpZy5oZWlnaHQ9MTB9CmdncGxvdCh0eF9nZW5lX21ldGEgJT4lIAogICAgICAgICBkcGx5cjo6ZmlsdGVyKHR4X2Jpb3R5cGUgJWluJSB0eF9iaW90eXBlX3RhcmdldHMgJiBuZXhvbj09IDIpKSArCiAgZ2VvbV9wb2ludCggYWVzKGV4b25pY19sZW4sIGludHJvbmljX2xlbiwgIGNvbG91cj1wZXJjX2dlbmVfZ2MpLAogICAgICAgICAgICAgIHNpemU9MC4yLAogICAgICAgICAgICAgIGFscGhhPTAuNSkgICsgIAogIHNjYWxlX3hfbG9nMTAoKSArCiAgIHNjYWxlX3lfbG9nMTAoKSArCiAgZmFjZXRfd3JhcCh+dHhfYmlvdHlwZSkgICsKICBzY2FsZV9jb2xvdXJfZ3JhZGllbnQyKG1pZHBvaW50PTEwLCBtaWQgPSAieWVsbG93IikKYGBgCgoKYGBge3IgZmlnLmhlaWdodD0xMH0KZ2dwbG90KHR4X2dlbmVfbWV0YSAlPiUgCiAgICAgICAgIGRwbHlyOjpmaWx0ZXIodHhfYmlvdHlwZSAlaW4lIHR4X2Jpb3R5cGVfdGFyZ2V0cyAmIG5leG9uPCAxMCAmIG5leG9uPiAxKSkgKwogIGdlb21fcG9pbnQoIGFlcyhleG9uaWNfbGVuLCBpbnRyb25pY19sZW4sICBjb2xvdXI9cGVyY19nZW5lX2djKSwKICAgICAgICAgICAgICBzaXplPTAuMiwKICAgICAgICAgICAgICBhbHBoYT0wLjUpICArICAKICBzY2FsZV94X2xvZzEwKCkgKwogICBzY2FsZV95X2xvZzEwKCkgKwogIGZhY2V0X3dyYXAofnR4X2Jpb3R5cGUpICArCiAgc2NhbGVfY29sb3VyX2dyYWRpZW50MihtaWRwb2ludD0xMCwgbWlkID0gInllbGxvdyIpCmBgYAoKYGBge3IgZmlnLmhlaWdodD0xMH0KZ2dwbG90KHR4X2dlbmVfbWV0YSAlPiUgCiAgICAgICAgIGRwbHlyOjpmaWx0ZXIodHhfYmlvdHlwZSAlaW4lIHR4X2Jpb3R5cGVfdGFyZ2V0cyAmIG5leG9uPj0gMTApKSArCiAgZ2VvbV9wb2ludCggYWVzKGV4b25pY19sZW4sIGludHJvbmljX2xlbiwgIGNvbG91cj1wZXJjX2dlbmVfZ2MpLAogICAgICAgICAgICAgIHNpemU9MC4yLAogICAgICAgICAgICAgIGFscGhhPTAuNSkgICsgIAogIHNjYWxlX3hfbG9nMTAoKSArCiAgIHNjYWxlX3lfbG9nMTAoKSArCiAgZmFjZXRfd3JhcCh+dHhfYmlvdHlwZSkgICsKICBzY2FsZV9jb2xvdXJfZ3JhZGllbnQyKG1pZHBvaW50PTEwLCBtaWQgPSAieWVsbG93IikKYGBgCgoKCgpgYGB7cn0Kc2Vzc2lvbkluZm8oKQpgYGA=